
package com.hlkj.pay.task;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.awt.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeSettleConfirmModel;
import com.alipay.api.domain.SettleConfirmExtendParams;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.request.AlipayTradeSettleConfirmRequest;
import com.alipay.api.response.AlipayTradeSettleConfirmResponse;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.common.IUploadService;
import com.hlkj.pay.app.merchant.IAcctAccountAppService;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelComplaintOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.alipay.dto.AlipayConfig;
import com.hlkj.pay.dto.merchant.MerchantAccessDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.gateway.merchant.IMerchantAccessGateway;
import com.hlkj.pay.gateway.order.impl.ChannelComplaintGatewayImpl;
import com.hlkj.pay.infrastructure.mapper.order.OrderComplaintChannelMapper;
import com.hlkj.pay.infrastructure.mapper.order.OrderComplaintHistoryMapper;
import com.hlkj.pay.infrastructure.mapper.order.OrderComplaintMapper;
import com.hlkj.pay.infrastructure.mapper.order.OrderReceiveMapper;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessAuthDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessInfoDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.merchant.fund.MerchantFundAccountConfigDO;
import com.hlkj.pay.infrastructure.model.order.*;
import com.hlkj.pay.service.common.ICommonAppConfigService;
import com.hlkj.pay.service.common.IWechatAppService;
import com.hlkj.pay.service.merchant.IMerchantAccessAuthService;
import com.hlkj.pay.service.merchant.IMerchantAccessService;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.vo.openapi.fund.req.OpenApiFundAccountBindReq;
import com.hlkj.pay.vo.order.req.ComplaintCompleteReq;
import com.hlkj.pay.vo.order.req.ComplaintReplyUserReq;
import com.hlkj.pay.vo.order.req.MerchantChannelSplitReq;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/29 10:43
 */
@Slf4j
@Configuration
@EnableAsync
public class CommonTasks {

    @Autowired
    private  IUploadService uploadService;
    @Autowired
    private  OrderReceiveMapper orderReceiveMapper;
    @Autowired
    private  OrderComplaintMapper orderComplaintMapper;
    @Autowired
    private OrderComplaintHistoryMapper orderComplaintHistoryMapper;
    @Autowired
    private  OrderComplaintChannelMapper orderComplaintChannelMapper;
    @Autowired
    private  ChannelComplaintGatewayImpl channelComplaintGateway;
    @Autowired
    private IWechatAppService wechatAppService;
    @Autowired
    private ICommonAppConfigService commonAppConfigService;
    @Autowired
    private IMerchantApplicationService merchantApplicationService;
    @Autowired
    private IMerchantAccessGateway merchantAccessGateway;
    @Autowired
    private IMerchantAccessService merchantAccessService;
    @Autowired
    private IMerchantAccessAuthService merchantAccessAuthService;
    @Autowired
    private IAcctAccountAppService acctAccountAppService;

    @Value("${hlkj.qrDomain}")
    private String qrDomain;

    @Value("${server.port:8020}")
    private String serverPort;

    @Value("${hlkj.task.port:8020}")
    private String taskPort;

    @Bean(name = "commonTask")
    public Executor commonTask() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心线程数
        executor.setMaxPoolSize(10); // 最大线程数
        executor.setQueueCapacity(1000); // 队列容量
        executor.setKeepAliveSeconds(60); // 线程空闲时间
        executor.setThreadNamePrefix("Async-common"); // 线程名称前缀
        executor.initialize();
        return executor;
    }

    /**
     * 每小时同步支付宝投诉数据
     */
    @Scheduled(cron = "0 0 */1 * * ?")
    public void syncAliComplaints() {
        if (!serverPort.equals(taskPort)) {
            log.info("当前 expireOrderPayJob port 非目标port serverPort:{},taskPort:{}", serverPort, taskPort);
            return;
        }
        log.info("syncAliComplaints start");
        // 查询支付宝渠道
        List<OrderComplaintChannelDO> complaintChannelDOList = orderComplaintChannelMapper.selectList(OrderComplaintChannelDO::getType,2);
        if(CollUtil.isNotEmpty(complaintChannelDOList)){
            for(OrderComplaintChannelDO channelDO:complaintChannelDOList){
                ChannelComplaintOrderContext channelComplaintOrderContext = new ChannelComplaintOrderContext();
                channelComplaintOrderContext.setOrderComplaintChannelDO(channelDO);

                channelComplaintOrderContext.setStartTime(DateUtil.beginOfHour(new Date()));
                channelComplaintOrderContext.setEndTime(DateUtil.endOfHour(new Date()));

                channelComplaintOrderContext.setProcessStatus(true);
                CommonResult<java.util.List<OrderComplaintDO>> detailsResult = channelComplaintGateway.queryComplaintPage(channelComplaintOrderContext);
                if(detailsResult.isSuccess()){
                    java.util.List<OrderComplaintDO> detailResps = detailsResult.getData();
                    List<OrderComplaintDO> detailDbs = orderComplaintMapper.selectList(OrderComplaintDO::getChannelId, channelDO.getId());
                    saveOrderComplaintData(detailResps,detailDbs);
                }
            }
        }
    }

    /**
     * 微信投诉详情异步同步数据
     * @param orderComplaintDO  投诉详情数据
     */
    @Async("commonTask")
    public void complaintSyncData(OrderComplaintDO orderComplaintDO, OrderComplaintHistoryDO orderComplaintHistoryDO,boolean add){
        // 获取详情数据
        OrderComplaintChannelDO orderComplaintChannelDO = orderComplaintChannelMapper.selectById(orderComplaintDO.getChannelId());
        ChannelComplaintOrderContext channelComplaintOrderContext = new ChannelComplaintOrderContext();
        channelComplaintOrderContext.setOrderComplaintChannelDO(orderComplaintChannelDO);
        channelComplaintOrderContext.setOrderComplaintDO(orderComplaintDO);
        channelComplaintOrderContext.setProcessStatus(true);
        channelComplaintGateway.queryComplaintDetail(channelComplaintOrderContext);
        if(channelComplaintOrderContext.isProcessStatus()){
            if(add){
                orderComplaintMapper.insert(orderComplaintDO);
            }else{
                orderComplaintMapper.updateById(orderComplaintDO);
            }
        }
        // 更新协商历史
        if(orderComplaintHistoryDO != null){
            // 判断时间是否一样
            OrderComplaintHistoryDO old = orderComplaintHistoryMapper.selectOne(OrderComplaintHistoryDO::getOperatorTime,orderComplaintHistoryDO.getOperatorTime());
            if(old == null){
                orderComplaintHistoryMapper.insert(orderComplaintHistoryDO);
            }else{
                orderComplaintHistoryDO.setId(old.getId());
                orderComplaintHistoryMapper.updateById(orderComplaintHistoryDO);
            }
        }
    }

    /**
     * 收款单同步二维码
     */
    @Async("commonTask")
    public void recptSyncQrData(Long id,String code){
        // 转发link
        String link = qrDomain+"/pages/receipt/receipt?code="+code;
        Image image = QrCodeUtil.generate(link, QrConfig.create());
        byte[] imageBytes = ImgUtil.toBytes(image,ImgUtil.IMAGE_TYPE_PNG);
        CommonResult<String> commonResult = uploadService.upload(imageBytes, CommonEnum.OssEnum.IMAGE);
        if(commonResult.isSuccess()){
            OrderReceiveDO update = new OrderReceiveDO();
            update.setId(id);
            update.setLink(commonResult.getData());
            orderReceiveMapper.updateById(update);
            log.info("recptSyncQrData 同步转发link成功,{}",commonResult.getData());
        }
        // 微信小程序码
        // String scene = "id="+id;
        // CommonAppDO commonAppDO = commonAppConfigService.detail(appid,CommonEnum.COMMON_APP_TYPE.WECHAT_MIN);
        // if(commonAppDO != null){
        //     CommonResult<File> wxResult = wechatAppService.getwxacodeunlimit(commonAppDO,RECEIVE_QR_PARE_URL,scene);
        //     if(wxResult.isSuccess()){
        //         CommonResult<String> uploadResult = uploadService.upload(FileUtil.readBytes(wxResult.getData()), CommonEnum.OssEnum.IMAGE);
        //         if(uploadResult.isSuccess()){
        //             log.info("recptSyncQrData 同步微信QrCode成功,{}",uploadResult.getData());
        //         }
        //     }
        // }
    }


    @Async("commonTask")
    public void complaintBatchReplyUser(OrderComplaintDO orderComplaintDO, ComplaintReplyUserReq complaintOrderUserReq){
        OrderComplaintChannelDO orderComplaintChannelDO = orderComplaintChannelMapper.selectById(orderComplaintDO.getChannelId());
        if(orderComplaintChannelDO == null){
            return;
        }
        ChannelComplaintOrderContext channelComplaintOrderContext = new ChannelComplaintOrderContext();
        channelComplaintOrderContext.setOrderComplaintChannelDO(orderComplaintChannelDO);
        channelComplaintOrderContext.setOrderComplaintDO(orderComplaintDO);
        channelComplaintOrderContext.setContent(complaintOrderUserReq.getContent());
        channelComplaintOrderContext.setImgUrls(complaintOrderUserReq.getImgUrls());
        channelComplaintOrderContext.setType(complaintOrderUserReq.getProcessCode());
        channelComplaintOrderContext.setReplyType(complaintOrderUserReq.getReplyType());
        channelComplaintOrderContext.setProcessStatus(true);
        channelComplaintGateway.replyUser(channelComplaintOrderContext);
    }


    @Async("commonTask")
    public void complaintBatchComplete(OrderComplaintDO orderComplaintDO, ComplaintCompleteReq complaintCompleteReq){
        OrderComplaintChannelDO orderComplaintChannelDO = orderComplaintChannelMapper.selectById(orderComplaintDO.getChannelId());
        if(orderComplaintChannelDO == null){
            return;
        }
        ChannelComplaintOrderContext channelComplaintOrderContext = new ChannelComplaintOrderContext();
        channelComplaintOrderContext.setOrderComplaintChannelDO(orderComplaintChannelDO);
        channelComplaintOrderContext.setOrderComplaintDO(orderComplaintDO);
        channelComplaintOrderContext.setProcessStatus(true);
        channelComplaintOrderContext.setContent(complaintCompleteReq.getContent());
        channelComplaintOrderContext.setType(complaintCompleteReq.getType());
        channelComplaintOrderContext.setImgUrls(complaintCompleteReq.getImgUrls());
        channelComplaintGateway.complete(channelComplaintOrderContext);

        // 更新协商历史
        if(CollUtil.isNotEmpty(channelComplaintOrderContext.getOrderComplaintHistoryDOList())){
            orderComplaintHistoryMapper.insertBatch(channelComplaintOrderContext.getOrderComplaintHistoryDOList());
        }
    }

    @Async("commonTask")
    public void easySplit(MerchantChannelSplitReq merchantChannelSplitReq){
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(merchantChannelSplitReq.getMchChannelCode());
        if (merchantAppChannelDO == null) {
            return;
        }
        MerchantAccessDto merchantAccessDto = merchantAccessService.domainDetail(merchantAppChannelDO.getAccessId());
        // 不判断通道状态
//        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
//            return CommonResult.error(OpenApiResultCode.MERCHANT_APP_CHANNEL_NOT_EFFECT);
//        }
//         if (!MerchantExtConstant.CHANNEL_EASY_PAY.equals(merchantAppChannelDO.getChannelCode())) {
//             return CommonResult.error(OpenApiResultCode.MERCHANT_APP_CHANNEL_NOT_EXIST);
//         }
        // 一次
        if(merchantChannelSplitReq.getNum() == null || merchantChannelSplitReq.getNum() == 0 || merchantChannelSplitReq.getNum() == 1){
            log.info("easySplit 拆分次数:1, req:{}",JsonUtils.toJsonString(merchantChannelSplitReq));
            CommonResult<MerchantAccessAuthDO> commonResult = merchantAccessGateway.easySplit(merchantAccessDto, merchantAppChannelDO, merchantChannelSplitReq);
            log.info("easySplit 请求：{}",JsonUtils.toJsonString(commonResult));
            MerchantAccessAuthDO accessAuthDO = commonResult.getData();
            if (accessAuthDO != null) {
                merchantAccessAuthService.saveMerchantAccessAuth(accessAuthDO);
            }
            if (!commonResult.isSuccess()) {
                log.info("easySplit 拆分失败,errMsg:{}",commonResult.getMsg());
            }else{
                log.info("easySplit 拆分成功");
            }
        }else{
            log.info("easySplit 拆分次数:{}, req:{}",merchantChannelSplitReq.getNum(), JsonUtils.toJsonString(merchantChannelSplitReq));
            for(int i=0; i<merchantChannelSplitReq.getNum(); i++){
                CommonResult<MerchantAccessAuthDO> commonResult = merchantAccessGateway.easySplit(merchantAccessDto, merchantAppChannelDO, merchantChannelSplitReq);
                log.info("easySplit num:{}, 请求：{}",i+1,JsonUtils.toJsonString(commonResult));
                MerchantAccessAuthDO accessAuthDO = commonResult.getData();
                if (accessAuthDO != null) {
                    merchantAccessAuthService.saveMerchantAccessAuth(accessAuthDO);
                }
                if (!commonResult.isSuccess()) {
                    log.info("easySplit 拆分失败,errMsg:{}",commonResult.getMsg());
                }else{
                    log.info("easySplit 拆分成功");
                }
            }
        }
    }

    /**
     *
     * 支付宝直付通资金结算异步
     */
    @Async("commonTask")
    public void alipayZftSettleConfirm(AlipayClient client, PayOrderDO payOrderDO, String settleNo, AlipayConfig alipayConfig){
        try {
            // 构造请求参数以调用接口
            AlipayTradeSettleConfirmModel model = new AlipayTradeSettleConfirmModel();
            model.setOutRequestNo(IdUtil.fastSimpleUUID());
            model.setTradeNo(payOrderDO.getChannelOrderNo());
            // 结算信息
            SettleInfo settleInfo = new SettleInfo();
            SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
            settleDetailInfo.setTransInType("loginName");
            settleDetailInfo.setTransIn(settleNo);
            settleDetailInfo.setAmount(NumberUtil.roundStr(payOrderDO.getAmount().doubleValue(),2));
            settleInfo.setSettleDetailInfos(CollUtil.newArrayList(settleDetailInfo));
            model.setSettleInfo(settleInfo);

            // 资金冻结
            SettleConfirmExtendParams confirmExtendParams = new SettleConfirmExtendParams();
            confirmExtendParams.setRoyaltyFreeze("true");
            model.setExtendParams(confirmExtendParams);

            AlipayTradeSettleConfirmRequest request = new AlipayTradeSettleConfirmRequest();
            request.setBizModel(model);

            log.info("支付宝直付通订单资金结算 请求参数:{}", JSONUtil.toJsonStr(model));
            AlipayTradeSettleConfirmResponse response = client.execute(request);
            log.info("支付宝直付通订单资金结算 响应参数:{}", JSONUtil.toJsonStr(response));
            if(response.isSuccess()){
                log.info("支付宝直付通订单资金结算 成功");
            }else{
                log.info("支付宝直付通订单资金结算 失败:{}", response.getSubMsg());
            }
        }catch (Exception e){
            log.error("支付宝直付通查询支付订单请求失败 message:{}", e.getMessage(), e);
        }
    }


    /**
     * 支付宝同步投诉分页数据
     * @return
     */
    @Async("commonTask")
    public CommonResult<Void> sycnComplaint(List<OrderComplaintChannelDO> channellist){
        // 多个channel
        for(OrderComplaintChannelDO channelDO:channellist){
            ChannelComplaintOrderContext channelComplaintOrderContext = new ChannelComplaintOrderContext();
            channelComplaintOrderContext.setOrderComplaintChannelDO(channelDO);
            channelComplaintOrderContext.setProcessStatus(true);
            CommonResult<java.util.List<OrderComplaintDO>> detailsResult = channelComplaintGateway.queryComplaintPage(channelComplaintOrderContext);
            if(detailsResult.isSuccess()){
                java.util.List<OrderComplaintDO> detailResps = detailsResult.getData();
                List<OrderComplaintDO> detailDbs = orderComplaintMapper.selectList(OrderComplaintDO::getChannelId, channelDO.getId());
                saveOrderComplaintData(detailResps,detailDbs);
            }
        }
        return CommonResult.success();
    }


    @Async("commonTask")
    public void accAccountBind(MerchantFundAccountConfigDO fundAccountConfigDO, MerchantAccessInfoDO merchantAccessInfoDO, String mchChannelCode){
        if(fundAccountConfigDO != null){
            log.info("addAppChannelInfo 渠道：{}，通道编码：{} 开通默认分账 请求参数:{}",merchantAccessInfoDO.getChannelCode(),mchChannelCode, JSONUtil.toJsonStr(fundAccountConfigDO));
            // 绑定默认的分账账号
            String accName = fundAccountConfigDO.getName();
            String accNo = fundAccountConfigDO.getAccountNo();
            Integer snVisible = fundAccountConfigDO.getSnVisible() == null ? 0: fundAccountConfigDO.getSnVisible();
            if(StrUtil.isNotEmpty(accName) && StrUtil.isNotEmpty(accNo)){
                // 分账比例
                OpenApiFundAccountBindReq bindReq = new OpenApiFundAccountBindReq();
                bindReq.setName(accName);
                bindReq.setAccountNo(accNo);
                bindReq.setFee(fundAccountConfigDO.getFee());
                bindReq.setRate(fundAccountConfigDO.getRate());
                bindReq.setMchChannelCode(mchChannelCode);
                bindReq.setSnVisible(snVisible);
                bindReq.setFundProcessType(1);
                CommonResult<Void> commonResult = acctAccountAppService.accountBind(bindReq);
                if(commonResult.isSuccess()){
                    log.info("addAppChannelInfo 渠道：{}，通道编码：{} 开通默认分账 成功",merchantAccessInfoDO.getChannelCode(),mchChannelCode);
                }else{
                    log.info("addAppChannelInfo 渠道：{}，通道编码：{} 开通默认分账 失败:{}", merchantAccessInfoDO.getChannelCode(),mchChannelCode,commonResult.getMsg());
                }
            }
        }
    }


    /**
     * 数据校对 有的就根据状态更新，没有就新增
     * @param detailResps 第三方返回的数据
     * @param detailDbs   本地数据库数据
     */
    private void saveOrderComplaintData(List<OrderComplaintDO> detailResps,List<OrderComplaintDO> detailDbs){

        if(CollUtil.isEmpty(detailDbs)){
            if(CollUtil.isNotEmpty(detailResps)){
                orderComplaintMapper.insertBatch(detailResps);
            }
        }else{
            if(CollUtil.isEmpty(detailResps)){
                return;
            }
            // 需要修改的结合
            List<OrderComplaintDO> updateList = new ArrayList<>();
            // 需要新增的结合
            List<OrderComplaintDO> addList = new ArrayList<>();
            // 本地投诉单号分组
            Map<String, OrderComplaintDO> detailDbsMap = detailDbs.stream()
                    .collect(Collectors.toMap(orderComplaintDO -> orderComplaintDO.getComplaintId(), Function.identity(), (t1, t2) -> t1));
            // 遍历 第三方返回的数据 比较
            detailResps.stream().forEach(orderComplaintDO -> {
                OrderComplaintDO orderComplaint = detailDbsMap.get(orderComplaintDO.getComplaintId());
                // 数据库没有
                if(orderComplaint == null){
                    addList.add(orderComplaintDO);
                }else{
                    BeanUtil.copyProperties(orderComplaintDO,orderComplaint, CopyOptions.create().setIgnoreNullValue(true));
                    updateList.add(orderComplaint);
                }
            });

            if(CollUtil.isNotEmpty(addList)){
                orderComplaintMapper.insertBatch(addList);
            }
            if(CollUtil.isNotEmpty(updateList)){
                orderComplaintMapper.updateBatch(updateList,updateList.size());
            }
        }

    }


}
